/*import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs
Window {
    width: 1280
    height: 960
    visible: true
    color: "#FFFFFFFF"
    title: qsTr("模板匹配")
    property real scaleFactor: 1.0
    property point dragOriginPos: Qt.point(0, 0)
    property point imageOriginPos: Qt.point(0, 0)
    property bool isDragging: false
    property url imageSource: ""
    Rectangle {
        id: rectangle
        //anchors.fill: parent
        color: "#00000000"
        border.color: "black"
        border.width: 2
        x: parent.x+50
        y: parent.y+50
        width: 800
        height: 640
        Canvas {
            id: chessboardCanvas
            anchors.fill: parent
            onPaint: {
                var ctx = getContext("2d");
                var width = chessboardCanvas.width;
                var height = chessboardCanvas.height;
                var squareSize = 20; // Assuming an 8x8 chessboard

                    // Clear the canvas
                ctx.clearRect(0, 0, width, height);

                    // Draw the chessboard
                for (var row = 0; row < height/squareSize; ++row) {
                    for (var col = 0; col <  width/squareSize; ++col) {
                        var x = col * squareSize;
                        var y = row * squareSize;

                            // Determine the fill color based on the row and column
                        var fillColor = (row + col) % 2 === 0 ? "#FFFFFF" : "#CCCCCC";
                        ctx.fillStyle = fillColor;
                        ctx.fillRect(x, y, squareSize, squareSize);
                    }
                }
            }

            Component.onCompleted: {
                chessboardCanvas.requestPaint();
            }
        }
        Image {
            id: imageDisplay
                //anchors.fill: parent
            anchors.centerIn: parent
            source: imageSource
            //fillMode: Image.PreserveAspectFit
            //transformOrigin: Item.TopLeft
            scale: scaleFactor
        }
        MouseArea{
            anchors.fill: imageDisplay
            hoverEnabled: true
            //cursorShape:Qt.PointingHandCursor
            onEntered: {
                cursorShape = Qt.OpenHandCursor  // 当鼠标进入区域时改变光标形状
            }

            onExited: {
                cursorShape = Qt.PointingHandCursor  // 当鼠标离开区域时恢复光标形状
            }
            onWheel: {
                var delta = wheel.angleDelta.y;
                if (delta > 0) {
                    scaleFactor *= 1.1;
                }
                else {
                scaleFactor /= 1.1;
                }
             // 限制最小缩放比例
                if (scaleFactor < 0.1) scaleFactor = 0.1;
            }

            onPressed:{
                imageDisplay.anchors.centerIn=undefined;
                cursorShape = Qt.ClosedHandCursor;
                isDragging=true;
                dragOriginPos = Qt.point(mouseX,mouseY);
                imageOriginPos = Qt.point(imageDisplay.x,imageDisplay.y);
                //console.log("mousePos:("+dragOrigin.x+","+dragOrigin.y+")");
            }
            onPositionChanged:{
                if (isDragging) {
                    var deltaX = mouseX - dragOriginPos.x;
                    var deltaY = mouseY - dragOriginPos.y;
                    var newX=imageOriginPos.x+deltaX;
                    var newY=imageOriginPos.y+deltaY;
                    // 限制图片不拖出窗口范围（可选）
                    if (newX < 0) newX = 0;
                    if (newY < 0) newY = 0;
                    if (newX + imageDisplay.width >parent.width) newX = parent.width - imageDisplay.width;
                    if (newY + imageDisplay.height >parent.height) newY =parent.height - imageDisplay.height;
                    console.log(imageDisplay.x);
                    imageDisplay.x=newX;
                    imageDisplay.y=newY;
                    dragOriginPos = Qt.point(mouseX,mouseY);
                    imageOriginPos = Qt.point(imageDisplay.x,imageDisplay.y);
                }
            }
            onReleased: {
                cursorShape = Qt.OpenHandCursor
                isDragging = false;
            }
        }
    }

    //对话框
    FileDialog {
        id: fileDialog
        title: "选择一张图片"
        nameFilters: ["Image files (*.png *.jpg *.jpeg *.bmp)"]
        onAccepted: {
            imageSource = fileDialog.currentFile
            imageDisplay.source = imageSource
            imageDisplay.anchors.centerIn=rectangle;
            console.log("Image loaded:", imageSource)
        }
        onRejected: {
            console.log("Canceled")
        }
        visible: false
    }
    //对话框按钮
    Button {
        id: imageButton
        x: 249
        y: 783
        width: 143
        height: 60
        visible: true
        text: qsTr("加载图片")
        autoRepeat: false
        checkable: false
        clip: false
        transformOrigin: Item.Center
        background: Rectangle {
            implicitWidth: 100
            implicitHeight: 40
            radius: 10 // 设置圆角半径
            border.color: imageButton.down ? "darkblue" : "blue" // 根据按下状态改变边框颜色
            border.width: 2 // 边框宽度
            color: imageButton.down ? "blue" : "lightblue" // 根据按下状态改变背景颜色
        }
        onClicked:{
            fileDialog.open()
        }
    }
}
*/
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs
import ImageProvider
import QtQuick.Layouts 2.15
Window {
    id: window
    visible: true
    property alias weakThreshLabelVerticalAlignment: weakThreshLabel.verticalAlignment
    width: 960
    height: 720
    minimumWidth: 480
    minimumHeight: 380
    title: qsTr("模板匹配")

    // 定义缩放比例系数变量,范围在(-10,10)之间
    property bool isTargetLoad: false;
    property double scaleValue: 1.1
    property int scaleLevel: 0
    property int imgWidth: 0
    property int imgHeight: 0
    
    property bool isTemplateLoad: false;
    property double templateScaleValue: 1.1
    property int templateScaleLevel: 0
    property int templateImgWidth: 0
    property int templateImgHeight: 0



    Rectangle{
        id:rRect;
        x:bgRect.x+bgRect.width
        y:bgRect.y
        width:300
        height:bgRect.height
        z:100
        color:"#FFFFFFFF"

        Label {
            id: createTemplateLabel
            x: 10
            y: 15
            width: 60
            height: 30
            text: "创建模板"
        }

        Label {
            id: weakThreshLabel
            x: 30
            y: 50
            width: 60
            height: 30
            text: "弱阈值"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter

            SpinBox {
                id: weakThreshSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                from:0
                to:255
                editable: true
                value:backend.weak_thresh
                stepSize:1
                onValueChanged: backend.weak_thresh=value
            }
        }

        Label {
            id: strongThreshLabel
            x: 30
            y: weakThreshLabel.y+40
            width: 60
            height: 30
            text: "强阈值"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter

            SpinBox {
                id: strongThreshSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                from:0
                to:255
                editable: true
                value:backend.strong_thresh
                stepSize:1
                onValueChanged: backend.strong_thresh=value;
            }

        }

        Label {
            id: angleStartLabel
            x: 30
            y: strongThreshLabel.y+40
            width: 60
            height: 30
            text: "起始角度"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: angleStartSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from:0
                value:backend.angleStart
                to: 36000
                stepSize:100
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', angleStartSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged: backend.angleStart=value;
            }
        }
        Label {
            id: angleExtentLabel
            x: 30
            y: angleStartLabel.y+40
            width: 60
            height: 30
            text: "角度范围"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: angleExtentSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from:0
                value:backend.angleExtent
                to: 36000
                stepSize:100
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', angleExtentSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged: backend.angleExtent=value;
            }
        }
        Label {
            id: angleStepLabel
            x: 30
            y: angleExtentLabel.y+40
            width: 60
            height: 30
            text: "角度步长"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: angleStepSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 0
                value: backend.angleStep
                to: 500
                stepSize: 50
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', angleStepSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged: backend.angleStep=value;
            }
        }

        Label {
            id: scaleMinLabel
            x: 30
            y: angleStepLabel.y+40
            width: 60
            height: 30
            text: "最小比例"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: scaleMinSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 30
                value: backend.scaleMin
                to: 200
                stepSize: 5
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', scaleMinSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100);
                }
               onValueChanged: backend.scaleMin=value;
            }
        }

        Label {
            id: scaleMaxLabel
            x: 30
            y: scaleMinLabel.y+40
            width: 60
            height: 30
            text: "最大比例"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: scaleMaxSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 30
                value: backend.scaleMax
                to: 200
                stepSize: 5
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', scaleMaxSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged: backend.scaleMax=value;
            }
        }

        Label {
            id: scaleStepLabel
            x: 30
            y: scaleMaxLabel.y+40
            width: 60
            height: 30
            text: "比例步长"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: scaleStepSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 0
                value: backend.scaleStep
                to: 200
                stepSize: 10
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', scaleStepSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged:backend.scaleStep=value;
            }
        }
        Label {
            id: findTemplateLabel
            x: 10
            y: scaleStepLabel.y+60
            width: 60
            height: 30
            text: "寻找模板"
        }
        Label {
            id: minScoreLabel
            x: 30
            y: findTemplateLabel.y+40
            width: 60
            height: 30
            text: "最小得分"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: minScoreSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 30
                value: backend.minScore
                to: 100
                stepSize: 10
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', minScoreSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged: backend.minScore=value;
            }
        }
        Label {
            id: maxOverlapLabel
            x: 30
            y: minScoreLabel.y+40
            width: 60
            height: 30
            text: "最大重叠"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: maxOverlapSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 0
                value: backend.maxOverlap
                to: 100
                stepSize: 5
                property int decimals: 2
                property real realValue: value / 100
                textFromValue: function(value, locale){
                    return Number(value / 100).toLocaleString(locale, 'f', maxOverlapSpinBox.decimals)
                }
                valueFromText: function(text, locale){
                    return Math.round(Number.fromLocaleString(locale, text) * 100)
                }
                onValueChanged: backend.maxOverlap=value;
            }
        }
        Label {
            id: numMatchesLabel
            x: 30
            y: maxOverlapLabel.y+40
            width: 60
            height: 30
            text: "目标数量"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            SpinBox {
                id: numsMatchesSpinBox
                x: 100
                y: 0
                width: 120
                height: 30
                editable: true
                from: 0
                value: backend.numMatches
                to: 100
                stepSize: 1
                onValueChanged: backend.numMatches=value;
            }
        }
        Label {
            id: getEdgesLabel
            x: 10
            y: numMatchesLabel.y+60
            width: 60
            height: 30
            text: "提取边缘"
        }
        Label {
            id: threshold1Label
            x: 30
            y: getEdgesLabel.y+40
            width: 60
            height: 30
            text: "阈值下限"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            Slider {
                id: threshold1Slider
                x: 100
                y: 0
                width: 120
                height: 30
                //editable: true
                from: 0
                value: backend.threshold1
                to: 255
                stepSize: 1
                onValueChanged: {
                    backend.threshold1=value;
                    backend.getTemplateEdges();
                }
                ToolTip.visible: threshold1Slider.pressed
                ToolTip.text: threshold1Slider.value.toString()
                //ToolTip.parent: threshold1Slider
                ToolTip.delay: 0  // 立即显示 ToolTip
            }
        }
        Label {
            id: threshold2Label
            x: 30
            y: threshold1Label.y+40
            width: 60
            height: 30
            text: "阈值上限"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            Slider {
                id: threshold2Slider
                x: 100
                y: 0
                width: 120
                height: 30
               // editable: true
                from: 0
                value: backend.threshold2
                to: 255
                stepSize: 1
                onValueChanged: {
                    backend.threshold2=value;
                    backend.getTemplateEdges();
                }
                ToolTip.visible: threshold2Slider.pressed
                ToolTip.text: threshold2Slider.value.toString()
                //ToolTip.parent: threshold2Slider
                ToolTip.delay: 0  // 立即显示 ToolTip
            }
        }
        Rectangle{
            id:templateRect;
            x:30
            y: threshold2Label.y+40
            clip:true
            width:rRect.width-80
            height:rRect.height-y
            color: "#000000FF"
            radius: 0
            border.color: "#000000"
            border.width: 5
            ToolTip{
            id:erasePositionTips
            x:0
            y:-30
            }
            Image {
                id: templateImage
               // x:0
                //y: numMatchesLabel.y+40
                //width:rRect.width
                //height:rRect.height-y
                asynchronous: false//刷新图片不闪烁
                //cache: true
                //anchors.fill: parent
                //anchors.centerIn: parent
                //fillMode: Image.PreserveAspectFit
                //fillMode: Image.PreserveAspectCrop
                //sourceSize.width: 10240
                //sourceSize.height: 10240
                visible:status === Image.Ready
                onStatusChanged: {
                    if (templateImage.status === Image.Loading) {
                       // busy.running = true
                       // stateLabel.visible = false
                    }

                    // 如果后面手动更改width height，则重新加载图片无法获取到真实大小了
                    else if(templateImage.status === Image.Ready){
                        //busy.running = false;
                        templateImgHeight = templateImage.height;
                        templateImgWidth = templateImage.width;
                    }else if(templateImage.status === Image.Error) {
                       // busy.running = false
                       // stateLabel.visible = true
                        //stateLabel.text = "Error"
                    }
                }
                Rectangle{
                    id:circleRect
                    width:10
                    height:10
                    color:"#FF0000"
                    radius:width/2
                    visible:false
                }
                MouseArea {
                    id: templateImageMouseArea
                    anchors.fill: templateImage
                    drag.target: templateImage
                   // drag.minimumX: -templateImage.width + parent.width  // 限制拖拽范围
                    //drag.maximumX: 0
                    //drag.minimumY: -templateImage.height + parent.height // 限制拖拽范围
                    //drag.maximumY: 0
                    // 设置鼠标悬停以及鼠标响应
                    hoverEnabled: true
                    onWheel: function WheelHandler(wheel){
                        templateImage.anchors.fill=undefined;
                        // 按中心缩放
                        // 在每次的基础上增加10%
                        /*var scaleBefore = imageViewer.scale;
                        var scaleDelta = imageViewer.scale * wheel.angleDelta.y / 120 / 10;
                        // delta = 0.01左右(10%) scale后这里xy不会变
                        //console.log("scale x/y="+imageViewer.x+imageViewer.y+"delta:"+scaleDelta)
                        imageViewer.scale += scaleDelta;*/

                        // 按鼠标缩放
                        if(wheel.angleDelta.y>0 && templateScaleLevel<=200){        // 图像放大处理
                            templateImage.transformOriginPoint.x = wheel.x;
                            templateImage.transformOriginPoint.y = wheel.y;
                            templateZoomIn(wheel.x,wheel.y);
                        }
                        else if(wheel.angleDelta.y< 0&& templateScaleLevel>=-100){ // 图像缩小处理
                            templateImage.transformOriginPoint.x = wheel.x;
                            templateImage.transformOriginPoint.y = wheel.y;
                            templateZoomOut(wheel.x,wheel.y);
                        }
                    }
                    acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
                    onPressed:(mouse)=>{
                        if(mouse.button===Qt.LeftButton){
                            drag.target=templateImage;
                            templateImage.anchors.fill=undefined;
                            cursorShape = Qt.ClosedHandCursor;
                        }
                        else if(mouse.button===Qt.RightButton){
                            drag.target=undefined;
                           // console.log(mouseX+","+mouseY);
                        }
                    }
                    onReleased:(mouse)=> {
                        cursorShape = Qt.ArrowCursor;
                        circleRect.visible=false;
                        erasePositionTips.visible=false;
                    }
                    onPositionChanged: (mouse)=>{
                        if(mouse.buttons&Qt.RightButton){
                            circleRect.x = mouseX - circleRect.width / 2; // 设置圆心在鼠标位置
                            circleRect.y = mouseY - circleRect.height / 2; // 设置圆心在鼠标位置
                            circleRect.visible =mouse.buttons&Qt.RightButton; // 显示圆
                            //var imageRect = templateImage.mapRectToItem(null, templateImage.boundingRect);
                            //var mousePosInImageSpace = templateImage.mapFromItem(templateImage, Qt.point(mouseX, mouseY));
                            //var imageWidth = imageRect.width;
                            //var imageHeight = imageRect.height;
                            //var mousePercentX = mousePosInImageSpace.x / imageWidth;
                            //var mousePercentY = mousePosInImageSpace.y / imageHeight;

                            const offsetX =(templateImage.width - templateImage.paintedWidth) / 2
                            const offsetY =(templateImage.height - templateImage.paintedHeight) / 2

                                                         // 2. 计算鼠标在图像显示区域内的相对坐标
                            const imageSpaceX = mouse.x - offsetX
                            const imageSpaceY = mouse.y - offsetY

                                                                    // 3. 计算缩放比例（假设宽高比一致）
                            const scaleX = templateImage.paintedWidth / templateImage.sourceSize.width;
                            const scaleY=templateImage.paintedHeight/templateImage.sourceSize.height;
                                                                    // 4. 转换为原始图像像素坐标
                            const pixelX = imageSpaceX / scaleX
                            const pixelY = imageSpaceY / scaleY
                            const pixelWidth=circleRect.width/scaleX
                            const pixelHeight=circleRect.height/scaleY
                            erasePositionTips.text = "Mouse position: (" + pixelX+ ", " +pixelY + ")";
                            //erasePositionTips.x = mouseX ; // 在鼠标位置旁边显示
                            //erasePositionTips.y = mouseY ;
                            erasePositionTips.delay=0;
                            erasePositionTips.visible=mouse.buttons&Qt.RightButton;
                            backend.erase(pixelX-pixelWidth/2,pixelY-pixelHeight/2,pixelWidth,pixelHeight);
                        }
                    }
                }
            }
            Rectangle {
                id: viewport
                width: templateRect.width // 视窗的初始宽度
                height: templateRect.height // 视窗的初始高度
                color: "#000000FF" // 半透明黑色背景，以便看到下面的图像
                border.color: "black"
                border.width: 5
                    // 平移变换
               // property point dragOffset: Qt.point(0, 0)
                //transform: Translate {
                 //   id: viewportTranslate
                  //  x: viewport.dragOffset.x
                   // y: viewport.dragOffset.y
                //}
            }
        }
    }
    //放大
    function templateZoomIn(x,y){
        var beforeWidth  = templateImage.width
        var beforeHeight = templateImage.height

        templateImage.width = templateImage.width   * templateScaleValue
        templateImage.height = templateImage.height * templateScaleValue
        templateImageMouseArea.width = templateImage.width
        templateImageMouseArea.height = templateImage.height

        templateImage.x = templateImage.x + x - templateImage.width  * x / beforeWidth
        templateImage.y = templateImage.y + y - templateImage.height * y / beforeHeight
        templateScaleLevel++
    }
    //缩小
    function templateZoomOut(x,y){
        var beforeWidth  = templateImage.width
        var beforeHeight = templateImage.height

        templateImage.width = templateImage.width   / templateScaleValue
        templateImage.height = templateImage.height / templateScaleValue
        templateImageMouseArea.width = templateImage.width
        templateImageMouseArea.height = templateImage.height
        templateImage.x = templateImage.x + x - templateImage.width  * x / beforeWidth
        templateImage.y = templateImage.y + y - templateImage.height * y / beforeHeight
        templateScaleLevel--
    }

    function templateZoomToFit(){
        templateImage.width = templateImgWidth;
        templateImage.height = templateImgHeight;

        //var height = Math.min(templateRect.height,templateImage.height);
        //var width = Math.min(templateRect.width,templateImage.width);
        var maxScale=Math.min(templateRect.height/templateImage.height,templateRect.width/templateImage.width);
        templateImage.height *=maxScale;
        templateImage.width *= maxScale;
       // if(height > templateRect.height){
        //    templateImage.height = template.height;
        //}
        //if(width > templateRect.width){
         //   templateImage.width = templateRect.width;
        //}
        templateImage.x = (templateRect.width-templateImage.width)/2;
        templateImage.y = (templateRect.height-templateImage.height)/2;

        //templateImageMouseArea.width = templateImage.width
        //templateImageMouseArea.height = templateImage.height
        //templateScaleLevel = Math.abs((templateImage.width-templateImgWidth)/templateImgWidth)*10;
        //var hScale = Math.abs((templateImage.height-templateImgHeight)/templateImgHeight)*10;
        //templateScaleLevel = Math.min(templateScaleLevel,hScale)*-1;
    }










    // 背景颜色
    Rectangle{
        id:bgRect;
        width:parent.width-300
        height:parent.height
        clip: true
        //anchors.verticalCenter: busy.verticalCenter
        //anchors.left: parent.left
        //anchors.right: parent.right
        //anchors.top: busy.bottom
        //anchors.bottom: parent.bottom
        //anchors.leftMargin: -510
        //color:"yellow";
        //anchors.rightMargin: -510
        //anchors.topMargin: -390
        //anchors.bottomMargin: -390
        //anchors.horizontalCenter: busy.horizontalCenter
        //gradient: Gradient {
        //    GradientStop { position: 0.0; color: "white"; }
        //    GradientStop { position: 0.2; color: "papayawhip"; }
        //   GradientStop { position: 0.5; color: "peachpuff"; }
        //   GradientStop { position: 0.8; color: "papayawhip"; }
        //   GradientStop { position: 1.0; color: "white"; }
        //}
        RoiRectangle{
            id:roiRectangle
            x:0
            y:0
            z:1
            width:200
            height:200
            borderWidth: 2
            borderColor:"#FF0000"
            handleSize: 9
        }
        Canvas {
            id: chessboardCanvas
            anchors.fill: parent
            z:0
            onPaint: {
                var ctx = getContext("2d");
                var width = chessboardCanvas.width;
                var height = chessboardCanvas.height;
                var squareSize = 20; // Assuming an 8x8 chessboard

                // Clear the canvas
                ctx.clearRect(0, 0, width, height);

                // Draw the chessboard
                for (var row = 0; row < height/squareSize; ++row) {
                    for (var col = 0; col <  width/squareSize; ++col) {
                        var x = col * squareSize;
                        var y = row * squareSize;

                        // Determine the fill color based on the row and column
                        var fillColor = (row + col) % 2 === 0 ? "#FFFFFF" : "#CCCCCC";
                        ctx.fillStyle = fillColor;
                        ctx.fillRect(x, y, squareSize, squareSize);
                    }
                }
            }

            Component.onCompleted: {
                chessboardCanvas.requestPaint();
            }
        }
        Image {
            id: imageViewer
            //asynchronous: true
            cache: false
            z:0
            smooth:true
            //anchors.fill: parent
            //anchors.centerIn: parent
            fillMode: Image.Stretch
            //sourceSize.width: 10240
            //sourceSize.height: 10240
            visible: status === Image.Ready
            //anchors.verticalCenter: chessboardCanvas.verticalCenter
            //anchors.left: chessboardCanvas.right
            //anchors.right: chessboardCanvas.left
            //anchors.top: chessboardCanvas.bottom
            //anchors.bottom: chessboardCanvas.top
            //anchors.horizontalCenter: chessboardCanvas.horizontalCenter
            onStatusChanged: {
                if (imageViewer.status === Image.Loading) {
                    busy.running = true
                    stateLabel.visible = false
                }

                // 如果后面手动更改width height，则重新加载图片无法获取到真实大小了
                else if(imageViewer.status === Image.Ready){
                    busy.running = false;
                    imgHeight = imageViewer.height;
                    imgWidth = imageViewer.width;
                }else if(imageViewer.status === Image.Error) {
                    busy.running = false
                    stateLabel.visible = true
                    stateLabel.text = "Error"
               }
            }
        }
        MouseArea{
            id: imageViewerMouseArea
            anchors.fill: imageViewer
            // 设置拖拽对象以及拖拽区域,横向纵向拖动
            drag.target: imageViewer
            drag.axis: Drag.XAndYAxis
            //drag.minimumX: -imageViewer.width/2;
            //drag.maximumX: imageViewer.width/2;
            //drag.minimumY: - imageViewer.height/2;
            //drag.maximumY: imageViewer.height/2;

            // 设置鼠标悬停以及鼠标响应
            hoverEnabled: true
            onWheel: function WheelHandler(wheel){
                // 按中心缩放
                // 在每次的基础上增加10%
                /*var scaleBefore = imageViewer.scale;
                var scaleDelta = imageViewer.scale * wheel.angleDelta.y / 120 / 10;
                // delta = 0.01左右(10%) scale后这里xy不会变
                //console.log("scale x/y="+imageViewer.x+imageViewer.y+"delta:"+scaleDelta)
                imageViewer.scale += scaleDelta;*/


                // 按鼠标缩放
                if(wheel.angleDelta.y>0 && scaleLevel<=1000){        // 图像放大处理
                    imageViewer.transformOriginPoint.x = wheel.x
                    imageViewer.transformOriginPoint.y = wheel.y
                    zoomIn(wheel.x,wheel.y)
                }
                else if(wheel.angleDelta.y< 0&& scaleLevel>=-1000){ // 图像缩小处理
                    imageViewer.transformOriginPoint.x = wheel.x
                    imageViewer.transformOriginPoint.y = wheel.y
                    zoomOut(wheel.x,wheel.y)
                }
            }

            onPressed: {
                cursorShape = Qt.ClosedHandCursor
            }
            onReleased: {
                cursorShape = Qt.ArrowCursor
            }
        }
    }

    BusyIndicator {
        id: busy
        running: false
        anchors.centerIn: bgRect
        //z: 2
    }

    // 错误信息
    Text {
        id: stateLabel
        visible: false
        anchors.centerIn: bgRect
        //z: 3
    }
    function zoomIn(x,y){
        var beforeWidth  = imageViewer.width;
        var beforeHeight = imageViewer.height;

        imageViewer.width = imageViewer.width   * scaleValue;
        imageViewer.height = imageViewer.height * scaleValue;
       // imageViewerMouseArea.width = imageViewer.width;
       // imageViewerMouseArea.height = imageViewer.height;

        imageViewer.x = imageViewer.x + x - imageViewer.width  * x / beforeWidth
        imageViewer.y = imageViewer.y + y - imageViewer.height * y / beforeHeight
        scaleLevel++
    }

    function zoomOut(x,y){
        var beforeWidth  = imageViewer.width
        var beforeHeight = imageViewer.height

        imageViewer.width = imageViewer.width   / scaleValue;
        imageViewer.height = imageViewer.height / scaleValue;
       // imageViewerMouseArea.width = imageViewer.width;
       // imageViewerMouseArea.height = imageViewer.height;
        imageViewer.x = imageViewer.x + x - imageViewer.width  * x / beforeWidth
        imageViewer.y = imageViewer.y + y - imageViewer.height * y / beforeHeight
        scaleLevel--
    }

    function zoomToFit(){
        imageViewer.width = imgWidth;
        imageViewer.height = imgHeight;
    //  var height = Math.min(bgRect.height,imageViewer.height);
    // var width = Math.min(bgRect.width,imageViewer.width);
        //imageViewer.height = height;
        //imageViewer.width = width;
        if(imageViewer.height > bgRect.height||imageViewer.height > bgRect.width){
            var maxScale=Math.min(bgRect.height/imageViewer.height,bgRect.width/imageViewer.width);
            imageViewer.height *=maxScale;
            imageViewer.width *= maxScale;

        }


        imageViewer.x = (bgRect.width-imageViewer.width)/2;
        imageViewer.y = (bgRect.height-imageViewer.height)/2;
        //imageViewerMouseArea.width = imageViewer.width;
       // imageViewerMouseArea.height = imageViewer.height;
        //scaleLevel = Math.abs((imageViewer.width-imgWidth)/imgWidth)*10;
        var hScale = Math.abs((imageViewer.height-imgHeight)/imgHeight)*10;
        //scaleLevel = Math.min(scaleLevel,hScale)*-1;
    }

    // 底部方框，用来放按钮
    Rectangle{
        id:toolBar
        height:50;
        width:parent.width*0.8;
        color: "#A04682B4";
        radius: 5;
        property int leftPos: (parent.width-width)/2;

//        anchors.left: parent.left;
        anchors.leftMargin: leftPos;
        anchors.bottom: parent.bottom;
        anchors.bottomMargin: 25;
        // 读取模板图像btn
        Button {
            id: openTemplateBtn
            text: "读取模板"
            anchors.left: parent.left
            width:70
            height:50
            //按下按钮，打开文件对话框
            onClicked: {
                templateFileDialog.open();
            }
            //z: 4
        }
        // 读取源图像btn
        Button {
            id: openTargetBtn
            text: "读取源图像"
            anchors.left: openTemplateBtn.right
            width:70
            height:50
            //按下按钮，打开文件对话框
            onClicked: {
                targetFileDialog.open()
            }
            //z: 4
        }
        // 打开文件夹btn
        Button {
            id: openTargetFolderBtn
            text: "打开文件夹"
            anchors.left: openTargetBtn.right
            width:70
            height:50
            //按下按钮，打开文件对话框
            onClicked: {
                targetFolderDialog.open()
            }
            //z: 4
        }
        // 旋转btn
        Button {
            id: roteteBtnL
            text: "左旋转"
            anchors.left: openTargetFolderBtn.right
            width:70
            height:50
            onClicked: {
                if(imageViewer.status != imageViewer.Null)
                    imageViewer.rotation -= 90;
            }
            //z: 4
        }
        Button {
            id: roteteBtnR
            text: "右旋转"
            anchors.left: roteteBtnL.right
            width:70
            height:50
            onClicked: {
                if(imageViewer.status != imageViewer.Null)
                    imageViewer.rotation += 90;
            }
            //z: 4
        }

        // 放大btn
        Button {
            id: zoomInBtn
            text: "放大"
            anchors.left: roteteBtnR.right
            width:70
            height:50
            onClicked: {
                //imageViewer.scale += imageViewer.scale * 0.1;
                zoomIn(imageViewer.width/2,imageViewer.height/2)
            }
        }
        Button {
            id: zoomOutBtn
            text: "缩小"
            anchors.left: zoomInBtn.right
            width:70
            height:50
            onClicked: {
                //imageViewer.scale -= imageViewer.scale * 0.1;
                zoomOut(imageViewer.width/2,imageViewer.height/2)
            }
        }
        Button {
            id: seeAllBtn
            text: "看全部"
            anchors.left: zoomOutBtn.right
            width:70
            height:50
            onClicked: {
                //imageViewer.scale = 1.0;

                // 先恢复大小
                zoomToFit();
            }
        }
        Button {
            id: actualSizeBtn
            text: "实际大小"
            anchors.left: seeAllBtn.right
            width:70
            height:50
            onClicked: {
                //imageViewer.scale = 1.0;
                imageViewer.x = 0;
                imageViewer.y = 0;
                imageViewer.width = imageViewer.sourcrSize.width;
                imageViewer.height = imageViewer.sourceSize.height;
                scaleLevel = 0;
            }
        }

        Button {
            id: createTemplateBtn
            text: "创建模板"
            anchors.left: actualSizeBtn.right
            width:70
            height:50
            onClicked: {
                backend.createTemplate();
            }
        }

        Button {
            id: findTemplateBtn
            text: "寻找模板"
            anchors.left: createTemplateBtn.right
            width:70
            height:50
            onClicked: {
                backend.findTemplate();
            }
        }
        Button {
            id: getEdgesBtn
            text: "提取边缘"
            anchors.left: findTemplateBtn.right
            width:70
            height:50
            onClicked: {
                backend.getTemplateEdges();
            }
        }
        Button {
            id: previousBtn
            text: "上一张"
            anchors.left: getEdgesBtn.right
            width:70
            height:50
            onClicked: {
                scaleLevel=0;
                imageViewer.x=0;
                imageViewer.y=0;
                imageViewer.width=undefined;
                imageViewer.height=undefined;
                isTargetLoad=true;
                backend.previous_target_image();
                if(findCheckBox.checked){backend.findTemplate();}
            }
        }
        Button {
            id: nextBtn
            text: "下一张"
            anchors.left:previousBtn.right
            width:70
            height:50
            onClicked: {
                scaleLevel=0;
                imageViewer.x=0;
                imageViewer.y=0;
                imageViewer.width=undefined;
                imageViewer.height=undefined;
                isTargetLoad=true;
                backend.next_target_image();
                if(findCheckBox.checked){backend.findTemplate();}
            }
        }
        CheckBox{
            id:findCheckBox
            text:"自动检测"
            anchors.left:nextBtn.right
            width:70
            height:50
            onCheckStateChanged: {
            }
        }
        Button {
            id: saveTemapletaBtn
            text: "保存模板"
            anchors.left:findCheckBox.right
            width:70
            height:50
            onClicked: {
                saveTargetFileDialog.open();
            }
        }
        Button {
            id: cropBtn
            text: "裁剪"
            anchors.left:saveTemapletaBtn.right
            width:70
            height:50
            onClicked: {
                const offsetX =(imageViewer.width - imageViewer.paintedWidth) / 2
                const offsetY =(imageViewer.height - imageViewer.paintedHeight) / 2

                                             // 2. 计算鼠标在图像显示区域内的相对坐标
                const imageSpaceX = roiRectangle.x+roiRectangle.width/2-imageViewer.x - offsetX
                const imageSpaceY = roiRectangle.y+roiRectangle.height/2-imageViewer.y - offsetY

                                                        // 3. 计算缩放比例（假设宽高比一致）
                const scaleX = imageViewer.paintedWidth / imageViewer.sourceSize.width;
                const scaleY=imageViewer.paintedHeight/imageViewer.sourceSize.height;
                                                        // 4. 转换为原始图像像素坐标
                const pixelX = imageSpaceX / scaleX
                const pixelY = imageSpaceY / scaleY
                const pixelWidth=roiRectangle.width/scaleX
                const pixelHeight=roiRectangle.height/scaleY

                templateScaleLevel=0;
                templateImage.x=0;
                templateImage.y=0;
                templateImage.width=undefined;
                templateImage.height=undefined;
                isTemplateLoad=true;
                backend.cropTargetImage(pixelX,pixelY, pixelWidth, pixelHeight,roiRectangle.rotation);
                //saveTargetFileDialog.open();
            }
        }
    }


    // 右边的文字
    Text {
        id: imageText
        anchors.top: parent.top
        anchors.right: parent.right
        anchors.rightMargin: 8
        font.pixelSize: 15
    }

    FileDialog {
        id: templateFileDialog
        title: "选择模板图片"
        nameFilters: ["Image Files (*.jpg *.png *.bmp)"]
        onAccepted: {
            templateScaleLevel=0;
            templateImage.x=0;
            templateImage.y=0;
            templateImage.width=undefined;
            templateImage.height=undefined;
            isTemplateLoad=true;
            // new String
            var imagePath=templateFileDialog.currentFile
            backend.loadTemplateImage(imagePath);

        }
    }

    FileDialog {
        id: targetFileDialog
        title: "选择源图片"
        nameFilters: ["Image Files (*.jpg *.png *.bmp)"]
        onAccepted: {
            scaleLevel=0;
            imageViewer.x=0;
            imageViewer.y=0;
            imageViewer.width=undefined;
            imageViewer.height=undefined;
            //imageViewer.fillMode=Image.PreserveAspectFit;
            var imagePath=targetFileDialog.currentFile
            isTargetLoad=true;
            backend.loadTargetImage(imagePath);
        }
    }
    FileDialog {
        id: saveTargetFileDialog
        title: "保存模板"
        fileMode: FileDialog.SaveFile
        //nameFilters: ["Image Files (*.jpg *.png *.bmp)"]
        onAccepted: {
            var imagePath=selectedFile.toString();
            console.log(imagePath);
            backend.saveTemplateImage(imagePath);
        }
    }
    Connections {
        target: backend
        function onImageProcessed(imagePath) {
            //console.log(imagePath);
            //templateImage.anchors.fill=templateImage.parent;
            imageViewer.source = "image://ImageProvider/"+imagePath ;
            if(isTargetLoad==true){
                zoomToFit();
                scaleLevel=0;
             //   console.log(imageViewer.height);
              //  console.log(imageViewer.paintedHeight);
               // console.log(imageViewer.width);
               // console.log(imageViewer.paintedWidth);
                isTargetLoad=false;
            }
        }

    }
    Connections {
        target: backend
        function onTemplateProcessed(imagePath) {
            //templateImage.anchors.fill=templateImage.parent;
            templateImage.source = "image://ImageProvider/"+imagePath ;
            if(isTemplateLoad==true){
                templateZoomToFit();
                isTemplateLoad=false;
            }
        }
    }
    ImageProvider {
        id: myImageProvider
    }
    FolderDialog {
        id: targetFolderDialog
        title: "选择文件夹"
        onAccepted: {
            scaleLevel=0;
            imageViewer.x=0;
            imageViewer.y=0;
            imageViewer.width=undefined;
            imageViewer.height=undefined;
            //imageViewer.fillMode=Image.PreserveAspectFit;
            var folderPath=targetFolderDialog.selectedFolder;
            console.log(folderPath);
            isTargetLoad=true;
            backend.loadTargetFolder(folderPath);
        }
    }
}
